<template>
  <div class="dataList_gantt" ref="dataListRef">
    <!-- 行 -->
    <div class="row" v-for="(item, rowIndex) in dataList_copy" :key="rowIndex">
      <!-- 行最终容器 -->
      <div
        ref="rowItemRef"
        class="row-item-list"
        data-target="row-item-list"
        @dragover="
          (e) => {
            onDragover(e, rowIndex)
          }
        "
        @dragenter="
          (e) => {
            onDragenter(e, rowIndex)
          }
        "
        @drop="
          (e) => {
            onDrop(e, index)
          }
        "
        @dragleave="
          (e) => {
            onDragleave(e, index)
          }
        "
      >
        <!-- 行中的每一项 -->
        <div
          class="row-item"
          v-for="(it, cloumnIndex) in item.ganttDetails"
          :key="cloumnIndex"
        >
          <item
            data-target="item"
            :detailData="it"
            :rowIndex="rowIndex"
            :cloumnIndex="cloumnIndex"
            :height="_rowHeight"
            @startPostion="onStartPostion"
            @dragItemMsg="onDragItemMsg"
            @rowCloumn="getRowCloumn"
            @dragover="
              (e) => {
                onDragover_item(e, it, rowIndex, cloumnIndex)
              }
            "
            @dragenter="
              (e) => {
                onDragenter_item(e, it, rowIndex, cloumnIndex)
              }
            "
            @drop="
              (e) => {
                onDrop_item(e, it, rowIndex, cloumnIndex)
              }
            "
            @dragleave="
              (e) => {
                onDragleave_item(e, it, rowIndex, cloumnIndex)
              }
            "
            @childEnter="isInChild = true"
            @childDrop="handleChildDrop"
            @childLeave="isInChild = false"
          />
        </div>
        <!-- 虚拟元素 只有在拖动进入当前行才显示 -->
        <div
          data-target="virtualEle"
          :style="{
            left: virtualEleX_start + 'px',
            width: virtualEle_width + 'px'
          }"
          class="virtual-ele"
          v-if="dragenterIndex === rowIndex && isDraging"
        >
          松开至此
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed, nextTick, ref, watch } from 'vue'
import item from './item.vue'

const emit = defineEmits(['update', 'scroll'])

const props = defineProps({
  rowItemWidth: {
    type: Number,
    default: 60
  },
  rowHeight: {
    type: Number,
    default: 50
  },
  curTime: {
    type: String,
    default: '2023-11-07 00:00:00'
  },
  dataList: {
    type: Array,
    default: () => [
      {
        ganttDetails: [
          {
            id: 1,
            startTime: '2023-11-07 00:00:00',
            endTime: '2023-11-07 3:00:00',
            productCode: '物料1',
            process: '工序1'
          },
          {
            id: 1,
            startTime: '2023-11-07 03:00:00',
            endTime: '2023-11-07 8:00:00',
            productCode: '物料1',
            process: '工序1'
          },
          {
            id: 2,
            startTime: '2023-11-07 08:00:00',
            endTime: '2023-11-07 10:00:00',
            productCode: '物料2',
            process: '工序2'
          }
        ]
      },
      {},
      {},
      {},
      {
        ganttDetails: [
          {
            id: 3,
            startTime: '2023-11-07 00:00:00',
            endTime: '2023-11-07 3:00:00',
            productCode: '物料1',
            process: '工序1'
          },
          {
            id: 4,
            startTime: '2023-11-07 08:00:00',
            endTime: '2023-11-07 10:00:00',
            productCode: '物料2',
            process: '工序2'
          }
        ]
      },
      {},
      {},
      {},
      {},
      {},
      {},
      {},
      {},
      {},
      {},
      {},
      {},
      {},
      {},
      {}
    ]
  }
})

watch(
  () => props.dataList,
  (newVal) => {
    console.log('甘特图数据', newVal)
    // update_position_by_time()
    nextTick(() => {
      dataList_copy.value = JSON.parse(JSON.stringify(newVal))
      update_position_by_time()
      // registerContextmenu()
      registerScroll()
    })
  },
  { immediate: true } // 测试数据 滚动时未注册registerScroll
)

const dataListRef = ref(null)
const _rowItemWidth = computed(() => props.rowItemWidth + 'px')
const _rowWidth = computed(() => props.rowItemWidth * 24 + 'px')
const _rowHeight = computed(() => props.rowHeight + 'px')
const _maxHeight = computed(() => props.rowHeight * 9 + 'px')
let dataList_copy = ref([])

// -------------时间 -> 位置------------------
// 通过时间更新位置信息
const update_position_by_time = () => {
  dataList_copy.value.forEach((item) => {
    item.ganttDetails =
      item.ganttDetails?.map((it) => {
        const { startTime, endTime } = it
        const [x_start, x_end] = timeToPosition(
          props.curTime,
          startTime,
          endTime
        )
        return {
          ...it,
          x_start,
          x_end
        }
      }) || []
  })
  console.log('处理之后的数据', dataList_copy.value)
}
// 时间转相对位置
const timeToPosition = (basisTime, startTime, endTime) => {
  // 基准时间转时间戳
  const basis_time = new Date(basisTime).getTime()
  // 开始时间转时间戳
  const start_time = new Date(startTime).getTime()
  // 结束时间转时间戳
  const end_time = new Date(endTime).getTime()
  // 时间戳差值
  const basis_to_start = start_time - basis_time
  const start_to_end = end_time - start_time
  const basis_to_end = end_time - basis_time
  // 一天时间戳
  let totalTime = 24 * 60 * 60 * 1000
  // 容器总长
  let totalWidth = props.rowItemWidth * 24
  // 相对位置
  let position_basis_to_start = (basis_to_start / totalTime) * totalWidth
  let position_basis_to_end = (basis_to_end / totalTime) * totalWidth
  let position_start_to_end = (start_to_end / totalTime) * totalWidth
  return [position_basis_to_start, position_basis_to_end, position_start_to_end]
}
// ---------------------------------------------------

// -------------------拖动进入、离开、释放-----------------------
let enterDom = null

let dragenterIndex = ref('')
const rowItemRef = ref(null)

watch(dragenterIndex, () => {
  // 进入哪一行，给哪一行添加drag-enter类
  dataList_copy.value.forEach((item, index) => {
    if (index === dragenterIndex.value) {
      rowItemRef.value[index].classList.add('drag-enter')
    } else {
      rowItemRef.value[index].classList.remove('drag-enter')
    }
  })
})
const onDragenter = (e, index) => {
  if (e.target.dataset.target === 'row-item-list') {
    enterDom = e.target
    dragenterIndex.value = index
  } else {
    enterDom = null
  }
}

const onDragover = (e, index) => {
  e.preventDefault()
  let pX = e.clientX - startX_item_drag
  const { x_start, x_end } = msg_item_drag
  // 拖动过程通过虚拟节点记录当前位置
  calculateVirtualDomPosition(x_start + pX, x_end - x_start)
}

const onDragleave = (e) => {
  if (enterDom === e.target) {
    dragenterIndex.value = ''
    console.log('离开 恢复数据', e.target)
    // 恢复数据
    // dataRecovery()
  }
}

// 在目标元素上同时鼠标放开时触发
const onDrop = (e) => {
  // 拖拽结束
  isDraging.value = false
  // 没有特殊情况都是在虚拟元素上松开
  if (e.target.dataset.target === 'virtualEle') {
    // 拖动松开，取虚拟节点位置作为最终位置
    let dragItem = Object.assign({}, msg_item_drag, {
      x_start: virtualEleX_start.value,
      x_end: virtualEleX_start.value + virtualEle_width.value
    })
    // 追加拖拽元素到新行
    dataList_copy.value[dragenterIndex.value].ganttDetails.push(dragItem)
    // 移除旧行元素
    dataList_copy.value[rowCloumn_item_drag.rowIndex].ganttDetails.splice(
      rowCloumn_item_drag.cloumnIndex,
      1
    )
    // 清除样式
    rowItemRef.value[dragenterIndex.value].classList.remove('drag-enter')
  } else {
    // 如果不是在虚拟元素上松开，则恢复数据
    // dataRecovery()
  }
}

let isInChild = false
let enterDom_item = null
// 记录 进入行上item项的item项详细数据
let drage_enter_msg = {}
const onDragenter_item = (e, it, rowIndex, cloumnIndex) => {
  if (it.id !== msg_item_drag.id) {
    drage_enter_msg = JSON.parse(JSON.stringify(it))
    console.log('进入 item项数据 999999999', drage_enter_msg)
    if (isInChild) {
      e.target.classList.add('drag-enter-item')
    } else if (e.target.dataset.target === 'item') {
      enterDom_item = e.target
      e.target.classList.add('drag-enter-item')
    }
  }
}

let virtualEleX_start = ref(0)
let virtualEle_width = ref(0)
const onDragover_item = (e, it, rowIndex, cloumnIndex) => {
  e.preventDefault()
  if (it.id !== msg_item_drag.id) {
    const { x_start, x_end } = msg_item_drag
    calculateVirtualDomPosition(
      dataList_copy.value[rowIndex].ganttDetails[cloumnIndex].x_start,
      x_end - x_start
    )

    console.log('拖拽元素:', x_start, x_end)
    dataList_copy.value[rowIndex].ganttDetails[cloumnIndex] = {
      ...it,
      ...{
        x_start: it.x_start + x_end - x_start,
        x_end: it.x_end + x_end - x_start
      }
    }
    console.log(
      '最新数据',
      dataList_copy.value[rowIndex].ganttDetails[cloumnIndex]
    )
  }
}

const calculateVirtualDomPosition = (start, width) => {
  virtualEleX_start.value = start
  virtualEle_width.value = width
}

// 拖拽离开 数据恢复
const dataRecovery = () => {
  dataList_copy.value = JSON.parse(JSON.stringify(props.dataList.value))
  update_position_by_time()
}

const onDrop_item = (e, it, rowIndex, cloumnIndex) => {
  // 拖拽结束
  isDraging.value = false
  if (it.id !== msg_item_drag.id) {
    isInChild = false
    e.target.classList.remove('drag-enter-item')
  }
}

const onDragleave_item = (e, it, rowIndex, cloumnIndex) => {
  if (it.id !== msg_item_drag.id) {
    if (e.target.dataset.target === 'item' && !isInChild) {
      console.log('离开 item项数据666666666666666', it)
      // 离开自身元素 且不在自身元素的子元素中
      e.target.classList.remove('drag-enter-item')
    }
  }
}

const handleChildDrop = () => {
  enterDom_item.classList.remove('drag-enter-item')
}

let startX_item_drag = ''
let msg_item_drag = {}
let isDraging = ref(false)
const onStartPostion = (x) => {
  isDraging.value = true
  startX_item_drag = x
}

const onDragItemMsg = (data) => {
  msg_item_drag = data
}

let rowCloumn_item_drag = {}
const getRowCloumn = (obj) => {
  rowCloumn_item_drag = obj
}
// -------------------------------------------------------

// 注册滚动事件
const registerScroll = () => {
  dataListRef.value.addEventListener('scroll', () => {
    emit('scroll', dataListRef.value.scrollTop)
  })
}

const updateScrollTop = (scrollTop) => {
  dataListRef.value.scrollTop = scrollTop
}

defineExpose({
  updateScrollTop
})
</script>

<style lang="scss" scoped>
::-webkit-scrollbar {
  height: 0;
  width: 0;
}
.dataList_gantt {
  height: v-bind(_maxHeight);
  width: v-bind(_rowWidth);
  border-bottom: 1px solid #ebeef5;
  overflow-y: auto;
  .row {
    width: v-bind(_rowWidth);
    height: v-bind(_rowHeight);
    box-sizing: border-box;
    border: 1px solid #ebeef5;
    border-top: none;
    overflow: hidden;
    .row-item-list {
      position: relative;
      height: calc(v-bind(_rowHeight) - 10px);
      width: v-bind(_rowWidth);
      margin: 5px 0;
      background-color: #f0f0f0;
      border: 1px solid #ebeef5;
      box-sizing: border-box;
      box-shadow: 0 0 2px #ccc;
      transition: all 0.3s;
      .virtual-ele {
        position: absolute;
        z-index: 1;
        top: 0;
        background-color: #fff;
        height: 100%;
        box-sizing: border-box;
        border: 2px dashed red;
      }
    }
    .drag-enter {
      border: 1px solid #1890ff;
      box-shadow: 0 0 5px #1890ff;
    }
    .drag-enter-item {
      border: 1px solid #ff5918;
      box-shadow: 0 0 5px #ff5918;
    }
  }
}
</style>
